package com.bill.concurrency.example.singleton;

import com.bill.concurrency.annotations.NotRecommend;
import com.bill.concurrency.annotations.NotThreadSafe;
import com.bill.concurrency.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

/**
 * 构建一个单例类。
 * 双重同步锁单例模式。
 * 不是线程安全的，原因如下：
 * 构建一个对象有三步：instance=new SingletonExample4();
 * CPU的指令来说：
 * 1.分配内存
 * 2.初始化对象 instance
 * 3.将instance 指向刚分配的地址。
 *
 * 在多线程环境中，CPU指令有可能会重排。
 * 则instance=new SingletonExample4();该语句有可能会重排成下面的顺序。
 * 1.分配内存
 * 2.将instance 指向刚分配的地址。
 * 3.初始化对象 instance
 *
 *  此时，当前线程处于CPU指令的第二部时，而其它线程，则可能取到了instance这个值，认为
 *  instance已经实例了，直接拿这个实例去使用。其实，当前线程还没有实例化完成。就会发生引用错误。
 */
@Slf4j
@NotThreadSafe
public class SingletonExample4 {
    //单例对象
    private static SingletonExample4 instance=null;
    /**
     * 私有构造器，一定要有。
     */
    private SingletonExample4(){

    }


    /**
     * 静态工厂方法。
     * 通过加入Synchronized 加入并发控制，构建线程安全的对象
     * 使用双重检测+锁 机制。
     *
     * @return
     */
    public static SingletonExample4 getInstance(){
        //双重检测机制
        if (instance==null){
            //同步锁
            synchronized (SingletonExample4.class){
                if(instance==null){
                    instance=new SingletonExample4();
                }
            }

        }
        return instance;
    }
}
